
#import "WWSet.h"
#import "WWInterp.h"

@implementation WWSet

+ initialize { return [WWSet setVersion:1], self; }


- init
{
  [super init];
  var = NULL;
  value = NULL;
  cmd = NULL;
  interp = nil;

  return self;
}

- initWithInterp:myInterp
{
  [super init];
  var = NULL;
  value = NULL;
  cmd = NULL;
  interp = myInterp;

  return self;
}

- free
{
  if (var)
  {  free(var);
  }
  if (value)
  {  free(value);
  }
  if (cmd)
  {  free(cmd);
  }

  return [super free];
}

// this is used only internally, for setting a copy without freeing the original
- _setVar:(const char *)newVar value:(const char *)newValue
{
  if (newVar)
  {  var = NXCopyStringBuffer(newVar);
  }
  else
  {  var = NULL;
  }

  if (newValue)
  {  value = NXCopyStringBuffer(newValue);
  }
  else
  {  value = NULL;
  }

  if (var && value)
  {  // cmd == "wwSet \"%s\" \"%s\""; i.e. 12 + strlen(var) + strlen(value)
     cmd = (char *)malloc(12 + strlen(var) + strlen(value));
     if (!cmd)
     {  NXLogError("WWSet: couldn't malloc memory for cmd!");
        return nil;
     }
     sprintf(cmd, "wwSet \"%s\" \"%s\"", var, value);
  }
  else
  {  NXLogError("WWSet: need to hand in non-NULL values for both var and value!");
     return nil;
  }
  return self;
}

- copyFromZone:(NXZone *)zone
{
   id   newCopy = [super copyFromZone:zone];

  [newCopy _setVar:var value:value];
  return newCopy;
}

- setVar:(const char *)newVar value:(const char *)newValue
{
  if (var)
  {  free(var);
  }
  if (newVar)
  {  var = NXCopyStringBuffer(newVar);
  }
  else
  {  var = NULL;
  }

  if (value)
  {  free(value);
  }
  if (newValue)
  {  value = NXCopyStringBuffer(newValue);
  }
  else
  {  value = NULL;
  }

  if (cmd)
  {  free(cmd);
  }
  if (var && value)
  {  // cmd == "wwSet \"%s\" \"%s\""; i.e. 12 + strlen(var) + strlen(value)
     cmd = (char *)malloc(12 + strlen(var) + strlen(value));
     if (!cmd)
     {  NXLogError("WWSet: couldn't malloc memory for cmd!");
        return nil;
     }
     sprintf(cmd, "wwSet \"%s\" \"%s\"", var, value);
  }
  else
  {  NXLogError("WWSet: need to hand in non-NULL values for both var and value!");
     return nil;
  }
  return self;
}

- (const char *)var { return (const char *)var; }
- (const char *)value { return (const char *)value; }
- (const char *)cmd { return (const char *)cmd; }



// WWRenderable protocol conformance stuff

- (BOOL)pushesOrPopsCTM { return NO; }
- (BOOL)pushesCTM { return NO; }
- (BOOL)popsCTM { return NO; }
- (BOOL)hasBoundingBox { return NO; }
- (RtBound *)boundingBoxStartingAt:(RtFloat)intervalStartTime endingAt:(RtFloat)intervalEndTime { return NULL; }
- calculateBoundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime { return self; }
- setBoundingBox:(RtBound *)newBoundingBox { return nil; }
- renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime usingStream:(NXStream *)ns { return self; } 
- renderMaps:(WW3DCamera *)camera usingStream:(NXStream *)ns { return self; }
- renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime { return self; } 
- renderMaps:(WW3DCamera *)camera { return self; } 
- renderSelfAsBox:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime { return self; } 
- preRenderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime { return self; }
- preRenderSelf:(WW3DCamera *)camera { return self; }

- renderSelf:(WW3DCamera *)camera  startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
{
  if (NXDrawingStatus != NX_DRAWING)
  {  RiArchiveRecord("comment", cmd); 
  }
  else
  {  [interp globalEval:cmd];
  }
  
  return self;
}

- renderSelf:(WW3DCamera *)camera
{
  RtFloat  shutterOpenTime = [camera shutterOpenTime],
           shutterCloseTime = [camera shutterCloseTime];


  return [self renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
}

- transformCTM:(WW3DAttributeState *)attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime { return self; }
- (BOOL)isMotionBlurrable { return NO; }
- (BOOL)isCompoundCommand { return NO; }
- (float)lastSampleIsAt { return 0.0; }
- (BOOL)isLerpable { return NO; }
- lerpWith:b by:(float)uValue { return nil; }
- lerpSelfWith:b by:(float)uValue { return nil; }
- (unsigned long int)maxSampleBandwidth 
{  if (cmd)
   {  return (unsigned long int)strlen(cmd);
   }
   return 0;
}

- writeEve:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "%s;", cmd); 
   return self;
}

- writeScene:(NXStream *)stream atTabLevel:(int)tab
{
   return [self writeEve:stream atTabLevel:tab];
}


- write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }

   NXPrintf(stream, "set __text__(color%s) {1 1 1}\n", [[self class] name]);
   NXPrintf(stream, "startShape %s; EveCmd {Color $__text__(color%s)}; ", [[self class] name], [[self class] name]);
   // need tab
   // need index (position in current list)
   NXPrintf(stream, 
	    "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n", 
            tab, index); 
   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "  EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
   [self writeEve:stream atTabLevel:tab];
   NXPrintf(stream, "} left;}\n");
  NXPrintf(stream, "endShape;\n");

  return self;
}


- writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "# ");
   [self writeEve:stream atTabLevel:tab];
   NXPrintf(stream, "\n");

   return self;
}

- (BOOL)theSameAs:otherRIBCommand
{
  if ([self class] != [otherRIBCommand class])
  {  return NO;
  }

  if (var)
  {  if (![otherRIBCommand var])
     {  return NO;
     }
     if (strcmp(var, [otherRIBCommand var]))
     {  return NO;
     }
  }
  if (value)
  {  if (![otherRIBCommand value])
     {  return NO;
     }
     if (strcmp(value, [otherRIBCommand value]))
     {  return NO;
     }
  }
  return YES;
}


- (BOOL)similarTo:otherRIBCommand 
{
  if ([self class] != [otherRIBCommand class])
  {  return NO;
  }
  return YES;
}


- (BOOL)isMoot { return NO;}

- (BOOL)isMootStartingAt:(float)startTime endingAt:(float)endTime  {  return [self isMoot];  }



#define typeVector "***"
#define typeValues &var, &value, &cmd

- read:(NXTypedStream*)stream 
{
    int version;
    [super read:stream];

    version = NXTypedStreamClassVersion(stream, "WWSet");
    if (version == 0) NXReadTypes(stream, "i", &version), version=1;
    if (version == 1)
    {  NXReadTypes(stream, typeVector, typeValues);
    } 
    else 
    {
    }
    return self;
}

- write:(NXTypedStream*)stream 
{
    [super write:stream];

    NXWriteTypes(stream, typeVector, typeValues);

    return self;
}

// boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
- class { return [super class]; }

@end
